#pragma once
#include <iostream>
#include <vector>
#include <semaphore.h>  
using namespace std;
template<class T>
class RingQueue
{
private:
    void P(sem_t& sem)     
    {
        sem_wait(&sem);
    }
    void V(sem_t& sem)
    {
        sem_post(&sem);
    }
    void Lock(pthread_mutex_t& mutex)
    {
        pthread_mutex_lock(&mutex);
    }
    void Unlock(pthread_mutex_t& mutex)
    {
        pthread_mutex_unlock(&mutex);
    }
public:
    RingQueue(int capacity = 5)
        :_cap(capacity), _ringqueue(capacity), _c_step(0), _p_step(0)
    {
        sem_init(&_c_data_sem, 0, 0);
        sem_init(&_p_space_sem, 0, capacity);
        pthread_mutex_init(&_c_mutex, nullptr);
        pthread_mutex_init(&_p_mutex, nullptr);
    }
    // 生产者生产（最开始只能是生产者线程先执行，因为最初的时候只有生产者能申请信号量成功）
    void push(const T& indata)  
    {
        // 申请空间信号量，空间资源减一
        P(_p_space_sem);
        Lock(_p_mutex);
        _ringqueue[_p_step++] = indata;
        // 下标循环
        _p_step %= _cap;
        indata->task();
        cout << indata->threadname << "  " << indata->task.Data() << endl;  
        Unlock(_p_mutex);
        // 生产完数据后，数据资源加一
        V(_c_data_sem);
    }
    // 消费者消费
    void pop() 
    {
        // 申请数据信号量，数据资源减一
        P(_c_data_sem);
        Lock(_c_mutex);
        T outdata = _ringqueue[_c_step++];
        // 下标循环
        _c_step %= _cap;            
        cout << "Customer: " << outdata->task.GetResult() << endl;
        delete outdata;
        Unlock(_c_mutex);
        // 消费完数据后，空间资源加一
        V(_p_space_sem);
    }
    ~RingQueue()
    {
        sem_destroy(&_c_data_sem);
        sem_destroy(&_p_space_sem);
        pthread_mutex_destroy(&_c_mutex);
        pthread_mutex_destroy(&_p_mutex);
    }
private:
    vector<T> _ringqueue;      // 适配vector容器为循环队列
    size_t _cap;               // 容量
    int _c_step;               // 消费者下标
    int _p_step;               // 生产者下标
    sem_t _c_data_sem;         // 消费者对应数据资源的信号量
    sem_t _p_space_sem;        // 生产者对应空间资源的信号量
    pthread_mutex_t _c_mutex;  // 用于消费者的互斥锁
    pthread_mutex_t _p_mutex;  // 用于生产者的互斥锁
};